﻿using System;
using System.ComponentModel;
using System.Drawing;
using System.IO;
using System.Windows.Forms;
using ESpace;

namespace ESpace_Project
{
    public partial class FormDBItem : Form
    {
        public FormDBItem()
        {
            InitializeComponent();
            ConstructDB(Application.StartupPath + "\\SaveDb.db");
        }
        
        // ШАБЛОН БАЗЫ ДАННЫХ

        #region ### МАНИПУЛЯЦИИ С БАЗОЙ ДАННЫХ ############################################################################

        #region *** Классы элементов *******************************************************

        // простой каталог с нулевым расширением
        public class DIR : DBItem
        {
            int ActVer = 0;

            public override string Ext { get { return ""; } }

            public DIR(string Name, DBItem Parent) : base(Name, true, Parent) { }

            public DIR(EStream st, DBItem Parent) : base(st, Parent) 
            {
                int LoadVer = st.LoadInt(); // задел на версионность 
            }

            public override void Save(EStream st)
            { 
                base.Save(st); 
                st.SaveInt(ActVer); 
            }

        }

        public class Note : DBItem
        {
            int ActVer = 0;

            public override string Ext { get { return "note"; } }

            public string Text;

            public Note(string Name, string Text, DBItem Parent)
                : base(Name, false, Parent)
            {
                this.Text = Text;
            }

            public Note(EStream st, DBItem Parent)
                : base(st, Parent)
            {
                int LoadVer = st.LoadInt(); // задел на версионность
                Text = st.LoadStr();
            }

            public override void Save(EStream st)
            {
                base.Save(st);
                st.SaveInt(ActVer);
                st.SaveStr(Text);
            }

        }

        #endregion *** Классы элементов *******************************************************

        #region *** переменные *************************************************************

        DIR db = new DIR(":", null);
        DBItem dir;
        int SelRec = -1;
        DBItem moveItem = null;
        bool bCutMoveItem = false;

        string fPathSaveDb;

        #endregion *** переменные *************************************************************

        /// <summary>Унимерсальная функция загрузки дочерней записи </summary>
        /// <param name="st">поток</param>
        /// <param name="ext">расширение, по которому смотрится, что за элемент загружать</param>
        /// <param name="Parent">родитель</param>
        public DBItem LoadRec(EStream st, string ext, DBItem Parent)
        {
            ext = ext.ToUpper();
            switch (ext)
            {
                case "": return new DIR(st, Parent);
                case "NOTE": return new Note(st, Parent);
            }
            return null;
        }

        /// <summary> Вызывается в конструкторе формы </summary>
        void ConstructDB(string fPathSaveDb)
        {
            this.fPathSaveDb = fPathSaveDb;
            ddlView.SelectedIndex = 0;

            DIR.LoadRec = new LoadRecDelegate(LoadRec);
            LoadDb();

            dir = db;
            ReFillList();
        }

        #region *** события ListView *******************************************************

        private void lvDB_SelectedIndexChanged(object sender, EventArgs e)
        {
            SelRec = -1;
            if (lvDB.SelectedIndices.Count == 0) return;
            SelRec = lvDB.SelectedIndices[0];
        }

        private void lvDB_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            if (SelRec != -1)
            {
                if (dir.Items[SelRec].IsDirectory)
                {
                    dir = (DIR)dir.Items[SelRec];
                    dir.Items.Sort();
                    ReFillList();
                }
            }
        }

        private void lvDB_AfterLabelEdit(object sender, LabelEditEventArgs e)
        {
            // если  отмена
            if (e.Label == null)
            {
                ;
            }
            // если подтверждение
            else
            {
                string newName = e.Label.Trim();
                if (newName == "") { ErrMess("Ошибка. Имя не может быть пустым"); e.CancelEdit = true; return; }

                // проверка имени
                int indFgr = dir.IndexOfRecord(newName);
                if (indFgr != -1 && indFgr != (e.Item))
                {
                    ErrMess("Ошибка. C таким именем уже существует другой элемент.");
                    e.CancelEdit = true;
                    return;
                }
                dir.Items[e.Item].Name = newName;

                /*dir.Items.Sort(); // сортировать нельзя из-за бага отрисовки после этого события в ListView
                ReFillList();*/

                SaveDB();

            }
        }

        private void lvDB_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter) lvDB_MouseDoubleClick(null, null);
            if (e.KeyCode == Keys.Back) btnUp_Click(null, null);
        }

        #endregion *** события ListView *******************************************************

        #region *** события меню ***********************************************************

        private void menuListMain_Opening(object sender, CancelEventArgs e)
        {
            mBtnAddDir.Enabled = false;
            mBtnAddRec.Enabled = false;
            mBtnDelItem.Enabled = false;
            mBtnCopy.Enabled = false;
            mBtnCut.Enabled = false;
            mBtnPaste.Enabled = false;

            if (SelRec == -1)
            {
                mBtnAddDir.Enabled = true;
                mBtnAddRec.Enabled = true;
                if (moveItem != null) mBtnPaste.Enabled = true;
            }
            else
            {
                mBtnDelItem.Enabled = true;
                mBtnCopy.Enabled = true;
                mBtnCut.Enabled = true;
            }
        }

        private void mBtnAddDir_Click(object sender, EventArgs e)
        {
            dir.Items.Add(new DIR(dir.GetUnicName("Каталог", ""), dir));
            dir.Items.Sort();
            SaveDB();
            ReFillList();
        }

        private void mBtnAddRec_Click(object sender, EventArgs e)
        {
            dir.Items.Add(new Note(dir.GetUnicName("Заметка", "note"), "Некоторый текст записи", dir));
            dir.Items.Sort();
            SaveDB();
            ReFillList();
        }

        private void mBtnDelItem_Click(object sender, EventArgs e)
        {
            if (MessageBox.Show("Действительно удалить?", "Удаление", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == System.Windows.Forms.DialogResult.Yes)
            {
                if (moveItem != null && dir.Items[SelRec].FullPath == moveItem.FullPath) moveItem = null;
                dir.Items.RemoveAt(SelRec);
                dir.Items.Sort();

                SaveDB();
                ReFillList();
            }
        }

        private void mBtnCopy_Click(object sender, EventArgs e)
        {
            if (SelRec != -1) moveItem = dir.Items[SelRec];
            bCutMoveItem = false;
        }

        private void mBtnCut_Click(object sender, EventArgs e)
        {
            if (SelRec != -1) moveItem = dir.Items[SelRec];
            bCutMoveItem = true;

            ReFillList();
            SelectItem(moveItem);
        }

        private void mBtnPaste_Click(object sender, EventArgs e)
        {
            DBItem destDir = dir;
            DBItem srsDir = moveItem.Parent;

            // нахождение номера перемещаемого элемента
            int indDir = srsDir.IndexOfRecord(moveItem.NameExt);

            // проверка на дубликат имени
            int duplInd = destDir.IndexOfRecord(moveItem.NameExt);
            if (duplInd != -1)
            {
                if (MessageBox.Show("Элемент с таким именем уже существует. Заменить существующий элемент?", "Вставка элемента", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == System.Windows.Forms.DialogResult.No)
                {
                    return;
                }
                destDir.Items.RemoveAt(duplInd);
            }

            if (bCutMoveItem) srsDir.Items.RemoveAt(srsDir.IndexOfRecord(moveItem.NameExt));
            moveItem.Parent = destDir;
            destDir.Items.Add(moveItem);
            destDir.Items.Sort();
            SelectItem(moveItem);
            SaveDB();
            moveItem = null;
            ReFillList();
        }

        #endregion *** события меню ***********************************************************

        #region *** прочие события *********************************************************

        private void btnUp_Click(object sender, EventArgs e)
        {
            if (dir.FullPath != db.FullPath) dir = dir.Parent;
            {
                dir.Items.Sort();
                ReFillList();
            }
        }

        private void ddlView_SelectedIndexChanged(object sender, EventArgs e)
        {
            switch (ddlView.SelectedIndex)
            {
                case 0: lvDB.View = View.LargeIcon; break;
                case 1: lvDB.View = View.SmallIcon; break;
                case 2: lvDB.View = View.List; break;
                case 3: lvDB.View = View.Tile; break;
                case 4: lvDB.View = View.Details; break;
            }
        }

        #endregion *** прочие события *********************************************************

        #region *** прочие фии *************************************************************

        void ReFillList()
        {
            SelRec = -1;

            // путь
            lblPath.Text = dir.FullPath + "\\*.*";

            lvDB.Items.Clear();

            lvDB.LargeImageList = imList;
            lvDB.SmallImageList = imList;

            for (int i = 0; i < dir.Items.Count; i++)
            {
                switch (dir.Items[i].Ext.ToUpper())
                {
                    case "":
                        if (bCutMoveItem == true && moveItem != null && moveItem.FullPath == dir.Items[i].FullPath)
                        {
                            lvDB.Items.Add(dir.Items[i].Name, 2);
                            lvDB.Items[lvDB.Items.Count - 1].ForeColor = Color.Gray;
                            lvDB.Items[lvDB.Items.Count - 1].SubItems.Add("<DIR>");
                        }
                        else
                        {
                            lvDB.Items.Add(dir.Items[i].Name, 0);
                            lvDB.Items[lvDB.Items.Count - 1].SubItems.Add("<DIR>");
                        }
                        break;
                    case "NOTE":
                        if (bCutMoveItem == true && moveItem != null && moveItem.FullPath == dir.Items[i].FullPath)
                        {
                            lvDB.Items.Add(dir.Items[i].Name, 3);
                            lvDB.Items[lvDB.Items.Count - 1].ForeColor = Color.Gray;
                            lvDB.Items[lvDB.Items.Count - 1].SubItems.Add(dir.Items[i].Ext);
                        }
                        else
                        {
                            lvDB.Items.Add(dir.Items[i].Name, 1);
                            lvDB.Items[lvDB.Items.Count - 1].SubItems.Add(dir.Items[i].Ext);
                        }
                        break;
                }

            }

        }

        void ErrMess(string mess)
        {
            MessageBox.Show(mess, "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }

        /// <summary>Выделение элемента в текущем каталоге</summary>
        void SelectItem(DBItem itm)
        {
            int ind = dir.IndexOfRecord(itm.NameExt);
            if (itm.Parent.FullPath != dir.FullPath) ind = -1;

            if (ind == -1) throw new Exception("Попытка выделить элемент, которого уже не существует");

            lvDB.SelectedIndices.Clear();
            lvDB.SelectedIndices.Add(ind);
        }

        #endregion *** прочие фии *************************************************************

        #region *** Save/Load **************************************************************

        void SaveDB()
        {
            EStream st = new EStream(fPathSaveDb);
            st.OpenSave();
            db.Save(st);
            st.Close();
        }

        void LoadDb()
        {
            if (!File.Exists(fPathSaveDb)) return;

            EStream st = new EStream(fPathSaveDb);
            st.OpenLoad();

            db = new DIR(st, null);

            st.Close();
        }

        #endregion *** Save/Load **************************************************************

        #endregion ### МАНИПУЛЯЦИИ С БАЗОЙ ДАННЫХ ############################################################################

        
        private void lvDB_ItemDrag(object sender, ItemDragEventArgs e)
        {
            lvDB.DoDragDrop(lvDB.SelectedItems, DragDropEffects.Move);
        }

        private void lvDB_DragEnter(object sender, DragEventArgs e)
        {
            int len = e.Data.GetFormats().Length - 1;
            int i;
            for (i = 0; i <= len; i++)
            {
                if (e.Data.GetFormats()[i].Equals("System.Windows.Forms.ListView+SelectedListViewItemCollection"))
                {
                    //The data from the drag source is moved to the target.	
                    e.Effect = DragDropEffects.Move;
                }
            }
        }

        private void lvDB_DragDrop(object sender, DragEventArgs e)
        {
            //Return if the items are not selected in the ListView control.
            if (lvDB.SelectedItems.Count == 0)
            {
                return;
            }
            //Returns the location of the mouse pointer in the ListView control.
            Point cp = lvDB.PointToClient(new Point(e.X, e.Y));
            //Obtain the item that is located at the specified location of the mouse pointer.
            ListViewItem dragToItem = lvDB.GetItemAt(cp.X, cp.Y);
            if (dragToItem == null)
            {
                return;
            }
            //Obtain the index of the item at the mouse pointer.
            int dragIndex = dragToItem.Index;
            ListViewItem[] sel = new ListViewItem[lvDB.SelectedItems.Count];
            for (int i = 0; i <= lvDB.SelectedItems.Count - 1; i++)
            {
                sel[i] = lvDB.SelectedItems[i];
            }
            for (int i = 0; i < sel.GetLength(0); i++)
            {
                //Obtain the ListViewItem to be dragged to the target location.
                ListViewItem dragItem = sel[i];
                int itemIndex = dragIndex;
                if (itemIndex == dragItem.Index)
                {
                    return;
                }
                if (dragItem.Index < itemIndex)
                    itemIndex++;
                else
                    itemIndex = dragIndex + i;
                //Insert the item at the mouse pointer.
                ListViewItem insertItem = (ListViewItem)dragItem.Clone();
                lvDB.Items.Insert(itemIndex, insertItem);
                //Removes the item from the initial location while 
                //the item is moved to the new location.
                lvDB.Items.Remove(dragItem);
            }
        }

        /*private void lvDB1_ItemDrag(object sender, ItemDragEventArgs e)
        {
            lvDB1.DoDragDrop(lvDB1.SelectedItems, DragDropEffects.Move);
        }

        private void lvDB1_DragEnter(object sender, DragEventArgs e)
        {
            int len = e.Data.GetFormats().Length - 1;
            int i;
            for (i = 0; i <= len; i++)
            {
                if (e.Data.GetFormats()[i].Equals("System.Windows.Forms.ListView+SelectedListViewItemCollection"))
                {
                    //The data from the drag source is moved to the target.	
                    e.Effect = DragDropEffects.Move;
                }
            }
        }

        private void lvDB1_DragDrop(object sender, DragEventArgs e)
        {
            //Return if the items are not selected in the ListView control.
            if (lvDB.SelectedItems.Count == 0)
            {
                return;
            }
            //Returns the location of the mouse pointer in the ListView control.
            Point cp = lvDB.PointToClient(new Point(e.X, e.Y));
            //Obtain the item that is located at the specified location of the mouse pointer.
            ListViewItem dragToItem = lvDB.GetItemAt(cp.X, cp.Y);
            if (dragToItem == null)
            {
                return;
            }
            //Obtain the index of the item at the mouse pointer.
            int dragIndex = dragToItem.Index;
            ListViewItem[] sel = new ListViewItem[lvDB1.SelectedItems.Count];
            for (int i = 0; i <= lvDB1.SelectedItems.Count - 1; i++)
            {
                sel[i] = lvDB1.SelectedItems[i];
            }
            for (int i = 0; i < sel.GetLength(0); i++)
            {
                //Obtain the ListViewItem to be dragged to the target location.
                ListViewItem dragItem = sel[i];
                int itemIndex = dragIndex;
                if (itemIndex == dragItem.Index)
                {
                    return;
                }
                if (dragItem.Index < itemIndex)
                    itemIndex++;
                else
                    itemIndex = dragIndex + i;
                //Insert the item at the mouse pointer.
                ListViewItem insertItem = (ListViewItem)dragItem.Clone();
                lvDB1.Items.Insert(itemIndex, insertItem);
                //Removes the item from the initial location while 
                //the item is moved to the new location.
                lvDB1.Items.Remove(dragItem);
            }
        }*/

    }

}
